﻿using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace FastDFS.Client
{
    public class TrackerGroup : ICloneable
    {
        private static readonly object Obj = new object();
        public int TrackerServerIndex;
        public IPEndPoint[] TrackerServers;

        public TrackerGroup(IPEndPoint[] trackerServers)
        {
            this.TrackerServers = trackerServers;
            this.TrackerServerIndex = 0;
        }

        /// <summary>
        ///return connected tracker server
        /// </summary>
        /// <param name="serverIndex"></param>
        /// <returns>connected tracker server, null for fail</returns>
        private async Task<TrackerServer> GetConnectionAsync(int serverIndex)
        {
            // var end = this.TrackerServers[serverIndex];
            var server = new TrackerServer(this.TrackerServers[serverIndex]);
            await server.TryConntectAsync();
            return server;
        }
        /// <summary>
        /// return connected tracker server
        /// </summary>
        /// <returns>connected tracker server</returns>
        public async Task<TrackerServer> GetConnectionAsync()
        {
            int currentIndex;

            lock (Obj)
            {
                this.TrackerServerIndex++;
                if (this.TrackerServerIndex >= this.TrackerServers.Length)
                {
                    this.TrackerServerIndex = 0;
                }

                currentIndex = this.TrackerServerIndex;
            }

            try
            {
                return await this.GetConnectionAsync(currentIndex);
            }
            catch (IOException)
            {
                Console.WriteLine("connect to server " + this.TrackerServers[currentIndex].Address + ":" + this.TrackerServers[currentIndex].Port + " fail");
            }

            for (int i = 0; i < this.TrackerServers.Length; i++)
            {
                if (i == currentIndex)
                {
                    continue;
                }

                try
                {
                    TrackerServer trackerServer = await this.GetConnectionAsync(i);

                    lock (Obj)
                    {
                        if (this.TrackerServerIndex == currentIndex)
                        {
                            this.TrackerServerIndex = i;
                        }
                    }

                    return trackerServer;
                }
                catch (IOException)
                {
                    Console.WriteLine("connect to server " + this.TrackerServers[i].Address + ":" + this.TrackerServers[i].Port + " fail");
                }
            }

            throw new FdfsException("no available tracker server");
        }

        public object Clone()
        {
            IPEndPoint[] trackerServers = new IPEndPoint[this.TrackerServers.Length];
            for (int i = 0; i < trackerServers.Length; i++)
            {
                trackerServers[i] = new IPEndPoint(this.TrackerServers[i].Address, this.TrackerServers[i].Port);
            }

            return new TrackerGroup(trackerServers);
        }
    }
}
